#pragma once

#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>

#ifdef strlen
#undef strlen
#endif
#define strlen(s) (s ? strlen(s) : 0)

#ifdef __cplusplus
extern "C" {
#endif
/*********************| 配置 |*********************/
#define ZYFP_LIB_VERSION	1
#define ZYFP_O_READ		0
#define ZYFP_O_WRITE		0x1

#ifdef ZYFP_DEBUG
#define zyfp_log(format, ...) fprintf(stdout, format, ##__VA_ARGS__)
#else
#define zyfp_log(...)	do{}while(0)
#endif

/*********************| 数据结构 |*********************/
// 数据包访问结构
typedef struct zyfp_handle_t zyfp_handle;

typedef struct {
	int16_t		version;
	int8_t		encrypt;
	int8_t		passmatch;
	uint32_t	filenum;
	time_t		packtime;
}zyfp_head;

#define ZYFP_ERR_NONE		0
#define ZYFP_ERR_SYS		-1
#define ZYFP_ERR_ARG		-2
#define ZYFP_ERR_PERMISSION	-3
#define ZYFP_ERR_PASSNOMATCH	-4
#define ZYFP_ERR_PACK		-5
#define ZYFP_ERR_PACKDAMAGE	-6
#define ZYFP_FILE_NOTFOUND	-7
#define ZYFP_VER_NOTMATCH	-8
/*********************| 方法 |*********************/
/**
 * @brief zyfp_init 以某种方式打开归档
 * @param ppath 归档文件路径
 * @param key 密钥
 * @param flag 打开方式READ或者WRITE
 * @return 返回文件操作结构体
 */
extern zyfp_handle*	zyfp_init(const char* ppath, const char* key, int flag);
/**
 * @brief zyfp_end 关闭归档。若是写入模式，此时会写入必要的头信息
 * @return 返回1表示写文件的时候生成的是空的包体
 */
extern int 		zyfp_end(zyfp_handle* ph);
/**
 * @brief zyfp_open 打开归档中的某文件
 * @param path 打包的文件路径
 * @return 负数表示失败，正数表示文件大小
 */
extern ssize_t		zyfp_open(zyfp_handle* ph, const char* path);
extern ssize_t		zyfp_open_ex(zyfp_handle* ph, const char* path, uint32_t pl);
/**
 * @brief zyfp_read 读取上一次打开的文件
 * @param n 读取多少字节
 * @param out 输出
 * @return 返回读取了多少字节.负数表示失败。当读取数小于要求数的时候表示到达文件尾部
 */
extern ssize_t		zyfp_read(zyfp_handle* ph, ssize_t n, char* out);
/**
 * @brief zyfp_readall  一次从头读取所有内容
 * @param out 输出。在不用的时候注意free掉
 * @return 负数表示失败，正数表示读取的文件大小。
 */
extern ssize_t		zyfp_readall(zyfp_handle* ph, char** out);
/**
 * @brief zyfp_seek 移动当前正打开的文件的文件指针
 * @param offset 偏移量
 * @param whence 从哪里开始偏移
 * @return 负数表示失败，0表示成功
 */
extern int		zyfp_seek(zyfp_handle* ph, long offset, int whence);

/**
 * @brief 获取当前在读文件的文件指针的位置
 */
extern ssize_t		zyfp_tell(const zyfp_handle* ph);

/**
 * @brief 判断是否到了当前打开文件的文件末尾
 * @return 返回1表示到了末尾，0表示不是，其它为错误码
 */
extern int		zyfp_eof(const zyfp_handle* ph);

/**
 * @brief zyfp_gethead 获取归档的文件头信息
 * @param out 输出
 * @return 负数表失败，0表示成功
 */
extern int		zyfp_gethead(const zyfp_handle* ph, zyfp_head* out);
/**
 * @brief zyfp_passmatch 密码是否匹配
 */
extern int		zyfp_passmatch(const zyfp_handle* ph);
/**
 * @brief 获取打包文件个数
 */
extern uint32_t		zyfp_packfilenum(const zyfp_handle* ph);
/**
 * @brief zyfp_add 以写方式打开归档后用次方法往包体添加数据
 * 不检测文件类型，请在上层检测保证写入的是文件不是文件夹
 * @param path 需要加入归档的文件路径
 */
extern int		zyfp_add(zyfp_handle* ph, const char* path, uint32_t pl);

/**
 * @brief zyfp_errmsg 获取错误信息
 * @param errno 错误码
 */
extern const char*	zyfp_errmsg(int err);

#ifdef __cplusplus
} /* end extern C */
#endif
